package com.shaoxi.ext.framework.impl;

import com.shaoxi.ext.framework.exception.RegisterExtException;
import com.shaoxi.ext.framework.ExtManager;
import com.shaoxi.ext.framework.IBusinessExt;
import com.shaoxi.ext.framework.exception.NotExtFoundException;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ExtManagerImpl implements ExtManager {

    //扩展点，key=bizCode
    private Map<String, List<IBusinessExt>> businessExtMap = new HashMap<>();

    @Override
    public void register(String bizCode, IBusinessExt iBusinessExt) throws RegisterExtException {
        //校验同一个业务是否已经有对应的实现
        IBusinessExt existExt = null;
        if(IBusinessExt.DEFAULT.equals(bizCode)){
            existExt = getDefaultExt(iBusinessExt.getClass());
        }else {
            existExt = findExt(businessExtMap.get(bizCode), iBusinessExt.getClass());
        }
        if(existExt !=null ){
            throw new RegisterExtException(String.format("扩展实现已存在。bizCode=%s class=%s", bizCode, existExt.getClass().getName()));
        }

        List<IBusinessExt> extList = businessExtMap.computeIfAbsent(bizCode, k -> new ArrayList<>());
        extList.add(iBusinessExt);
    }

    @Override
    public <T> T getExt(String bizCode, Class<T> cls) throws NotExtFoundException {
        //优先查找业务实现，找不到再找默认实现
        List<IBusinessExt> extList = businessExtMap.get(bizCode);
        T ext = findExt(extList, cls);

        if(ext==null){
            ext = getDefaultExt(cls);
        }

        if(ext==null){
            throw new NotExtFoundException();
        }

        return ext;
    }

    /**
     * 获取默认实现
     * @param cls
     * @return
     * @param <T>
     */
    private <T> T getDefaultExt(Class<T> cls){
        List<IBusinessExt> defaultExtList = businessExtMap.get(IBusinessExt.DEFAULT);
        return findExt(defaultExtList, cls);
    }

    /**
     *
     * @param extList
     * @param cls
     * @return
     * @param <T>
     */
    private <T> T findExt(List<IBusinessExt> extList, Class<T> cls){
        if(extList==null){
            return null;
        }

        for(IBusinessExt ext : extList){
            if(cls.isInstance(ext)){
                return (T)ext;
            }
        }
        return null;
    }
}
